<script lang="ts" setup>
import { ref, watch } from 'vue';

import { ElMessage, ElText, ElUpload } from 'element-plus';

const emits = defineEmits(['change']);
const modelValue = defineModel<(Blob | object | string)[]>('modelValue', {
  default: [],
});
const imageList = ref<any[]>([]);
const isCompressing = ref(false);

// 压缩配置
const compressConfig = ref({
  quality: 0.8, // 压缩质量 (0-1)
  maxWidth: 1920, // 最大宽度
  maxHeight: 1080, // 最大高度
  convertType: 'image/jpeg', // 目标格式
});

// 图片压缩核心方法
const compressImage = (file: File) => {
  return new Promise<File>((resolve, reject) => {
    const img = new Image();
    const reader = new FileReader();

    reader.addEventListener('load', (e) => {
      img.src = e.target?.result as string;

      img.addEventListener('load', () => {
        // 创建canvas
        const canvas = document.createElement('canvas');
        const ctx = canvas.getContext('2d')!;

        // 计算缩放比例
        let width = img.width;
        let height = img.height;

        if (width > compressConfig.value.maxWidth) {
          height *= compressConfig.value.maxWidth / width;
          width = compressConfig.value.maxWidth;
        }
        if (height > compressConfig.value.maxHeight) {
          width *= compressConfig.value.maxHeight / height;
          height = compressConfig.value.maxHeight;
        }

        // 设置canvas尺寸
        canvas.width = width;
        canvas.height = height;

        // 绘制压缩图像
        ctx.drawImage(img, 0, 0, width, height);

        // 转换为目标格式
        canvas.toBlob(
          (blob) => {
            if (!blob) {
              reject(new Error('图片压缩失败'));
              return;
            }

            // 生成新文件名
            const newFile = new File([blob], file.name, {
              type: compressConfig.value.convertType,
              lastModified: Date.now(),
            });

            resolve(newFile);
          },
          compressConfig.value.convertType,
          compressConfig.value.quality,
        );
      });
    });

    reader.onerror = (error) => reject(error);
    reader.readAsDataURL(file);
  });
};

const onChange = async (uploadFile) => {
  try {
    isCompressing.value = true;
    const rawFile = uploadFile.raw;

    // 文件类型验证
    if (!rawFile.type.startsWith('image/')) {
      throw new Error('请选择图片文件');
    }

    // 执行压缩
    const compressedFile = await compressImage(rawFile);

    // 创建预览URL
    const previewUrl = URL.createObjectURL(compressedFile);

    // 更新预览列表
    // imageList.value.push({
    //   preview: previewUrl,
    //   name: compressedFile.name,
    //   rawFile: uploadFile,
    // });

    // 更新model值
    // modelValue.value = [
    //   ...modelValue.value,
    //   {
    //     imageOssObjectKey: '',
    //     imageUrl: uploadFile,
    //   },
    // ];
    modelValue.value = [
      {
        imageOssObjectKey: '',
        imageUrl: uploadFile,
        bizType: 'CAR_IMAGE',
      },
    ];

    // 发出变更事件
    emits('change', {
      preUrl: previewUrl,
      file: uploadFile,
    });

    // 替换原始文件为压缩后的文件
    uploadFile.raw = compressedFile;
  } catch (error) {
    ElMessage.error(error.message || '图片处理失败');
  } finally {
    isCompressing.value = false;
  }
};

const removeImage = (index: number) => {
  imageList.value.splice(index, 1);
  modelValue.value.splice(index, 1);
};

watch(
  modelValue,
  (newValue) => {
    console.log('newValue', newValue);
    if (newValue.length === 0) {
      imageList.value = [];
    } else {
      imageList.value =
        newValue.map((item) => {
          // 区分字符串和Blob(File)类型
          return typeof item.imageUrl === 'string'
            ? {
                preview: item.imageUrl,
                name: item.imageUrl.split('/').pop(),
                rawFile: item.imageUrl,
                key: item?.imageOssObjectKey,
              }
            : {
                preview: URL.createObjectURL(item.imageUrl.raw),
                name: item.imageUrl.name,
                rawFile: item.imageUrl,
                key: item?.imageOssObjectKey,
              };
        }) || [];
    }
  },
  { deep: true },
);
const handleDragStart = (event, file) => {
  // 图片列表
  const imgList = imageList.value;

  const index = imgList.indexOf(file);

  event.dataTransfer.setData('index', index.toString());
};
const handleDrop = (event, file) => {
  // 获取目标位置索引
  const index = imageList.value.indexOf(file);

  // 阻止默认行为
  event.preventDefault();

  // 获取拖拽源索引
  const draggedIndex = Number(event.dataTransfer.getData('index'));

  // 创建数组副本（保证响应式更新）
  const updatedList = [...imageList.value];

  // 执行数组元素移动
  const [draggedItem] = updatedList.splice(draggedIndex, 1);
  updatedList.splice(index, 0, draggedItem);

  // 更新对应类型的图片列表
  imageList.value = updatedList;
  modelValue.value = updatedList.map((item) => {
    return {
      imageOssObjectKey: item?.key,
      imageUrl: item.rawFile,
    };
  });
};
</script>

<template>
  <div class="image-upload">
    <ElUpload
      :auto-upload="false"
      :disabled="isCompressing"
      :on-change="onChange"
      :show-file-list="false"
      accept="image/*"
      action="#"
      class="upload-demo"
      drag
      multiple
    >
      <div class="flex w-full justify-center">
        <div>
          <div class="el-upload__text">
            {{ isCompressing ? '正在压缩...' : '拖拽或点击上传图片' }}
          </div>
          <div class="el-upload__tip">
            支持JPG/PNG/WebP格式，自动压缩至1920×1080
          </div>
        </div>
      </div>
    </ElUpload>
    <!-- 图片预览区域 -->
    <div v-if="imageList.length > 0" class="preview-list">
      <div
        v-for="(image, index) in imageList"
        :key="index"
        class="preview-item"
        draggable="true"
        @dragover.prevent
        @dragstart="handleDragStart($event, image)"
        @drop="handleDrop($event, image)"
      >
        <img :alt="image.name" :src="image.preview" class="preview-image" />
        <div class="preview-info">
          <span class="preview-name">{{ image.name }}</span>
          <span class="preview-label">（已压缩优化）</span>
        </div>
        <div class="preview-remove" @click.stop="removeImage(index)">
          <i class="el-icon-delete">×</i>
        </div>
      </div>
    </div>
    <ElText class="mx-1" type="danger">
      该图片会直接展示至用户端的车型中，请谨慎上传！
    </ElText>
  </div>
</template>

<style scoped>
.image-upload {
  width: 100%;
  max-width: 800px;
  margin: 0 auto;
}

.upload-area {
  width: 100%;
  padding: 40px;
  text-align: center;
  cursor: pointer;
  border: 2px dashed #ddd;
  border-radius: 6px;
  transition: border-color 0.3s;
}

.upload-area:hover:not([disabled]) {
  border-color: #409eff;
}

.el-upload__tip {
  margin-top: 10px;
  font-size: 12px;
  color: #909399;
}

.preview-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 20px;
  margin-top: 20px;
}

.preview-item {
  position: relative;
  overflow: hidden;
  border-radius: 6px;
  box-shadow: 0 2px 12px rgb(0 0 0 / 10%);
}

.preview-image {
  width: 100%;
  height: 150px;
  object-fit: cover;
}

.preview-info {
  padding: 8px;
  background: #f5f7fa;
}

.preview-name {
  display: block;
  overflow: hidden;
  font-size: 14px;
  color: #606266;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.preview-label {
  font-size: 12px;
  color: #909399;
}

.preview-remove {
  position: absolute;
  top: 5px;
  right: 5px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  color: white;
  cursor: pointer;
  background: rgb(0 0 0 / 50%);
  border-radius: 50%;
  opacity: 0;
  transition: opacity 0.3s;
}

.preview-item:hover .preview-remove {
  opacity: 1;
}

/* 压缩状态样式 */
.upload-area[disabled] {
  cursor: not-allowed;
  opacity: 0.7;
}
</style>
